package com.hl.tools;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.hl.annotations.Autowired;
import com.hl.annotations.Controller;
import com.hl.annotations.RequestMapping;
import com.hl.annotations.Server;
import com.hl.bean.MethodInvokeBean;

public class LoadMap {
	private static Map<String, MethodInvokeBean> requestMappingMap=new HashMap<String,MethodInvokeBean>();
	private static Map<String, Object> serverMap=new HashMap<String,Object>();
	private static Map<String, Object> controllerMap=new HashMap<String,Object>();
	private static List<Class> classes=new ArrayList<Class>();
	static{
		//加载所有类
		List<String> classNames=ScanTools.getClassName("");
		for(String className:classNames){
			try {
				//获取所有的类模版
				//不用Class.forName()是因为会触发static{}
				Class<?> c=Thread.currentThread().getContextClassLoader().loadClass(className);
				if(!c.isAnnotation()&&!c.isEnum()&&!c.isInterface()){//不加载注解，枚举以及接口
					classes.add(c);
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		
		try {
			init();
		} catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * 加载Server注解的类
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 */
	private static void loadServer() throws InstantiationException, IllegalAccessException{
		for(Class c:classes){
			if(c.getAnnotation(Server.class)!=null){//判断是否有Server注解
				//获取类实现的接口
				Class[] is=c.getInterfaces();
				//生成对象
				Object o=c.newInstance();
				for(Class i:is){
					//存入serverMap中以接口名为key  后面实现自动注入
					serverMap.put(i.getName(), o);
				}
			}
		}
	}
	/**
	 * 加载带有Controller注解的类
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	private static void loadController() throws InstantiationException, IllegalAccessException{
		for(Class c:classes){
			if(c.getAnnotation(Controller.class)!=null){//判断是否有Controller注解
				if(controllerMap.containsKey(c.getName())){
//					throw new Exception("");//抛出异常  已存在类
				}
				controllerMap.put(c.getName(),c.newInstance());
			}
		}
	}
	/**
	 * 加载带有Autowired和RequestMapping注解的类
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	private static void loadAutowiredAndRequestMapping() throws IllegalArgumentException, IllegalAccessException{
		for(Object o:controllerMap.values()){
			Class c=o.getClass();
			Field[] fs=c.getDeclaredFields();//获取类的所有属性
			for(Field f:fs){
				if(f.getAnnotation(Autowired.class)!=null){
					if(!serverMap.containsKey(f.getType().getName())){
//						throw new Exception("");//抛出异常  没有该类的实现类或者该类的实现类没有添加注解
					}
					f.setAccessible(true);//获取权限
					f.set(o, serverMap.get(f.getType().getName()));
				}
			}
			Method[] ms=c.getMethods();//获取类的所有方法
			for(Method m:ms){
				if(m.getAnnotation(RequestMapping.class)!=null){
					StringBuilder sb=new StringBuilder();
					if(c.getAnnotation(RequestMapping.class)!=null){//判断类是否有RequestMapping注解
						RequestMapping r=(RequestMapping)c.getAnnotation(RequestMapping.class);
						sb.append(r.value());
					}else{
						sb.append("");
					}
					sb.append("/");
					RequestMapping r=(RequestMapping)m.getAnnotation(RequestMapping.class);
					sb.append(r.value());
					String path=sb.toString().replaceAll("/+", "/");
					requestMappingMap.put(path, new MethodInvokeBean(o, m));
				}
			}
		}
	}
	/***
	 * 初始化
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	private static void init() throws IllegalArgumentException, IllegalAccessException, InstantiationException{
		loadServer();
		loadController();
		loadAutowiredAndRequestMapping();
	}
	
	public static void run(String path){
		MethodInvokeBean bean=requestMappingMap.get(path);
		if(bean!=null){
			bean.invoke();
		}
	}
}
